package com.xqls.server.netty;

import com.alibaba.fastjson.JSON;
import com.xqls.bean.OperationRecordBean;
import com.xqls.biz.SokectBiz;
import com.xqls.dal.model.DeviceSchema;
import com.xqls.server.dto.SoketCommonDto;
import com.xqls.server.dto.recive.ControlApparatusDto;
import com.xqls.server.dto.recive.SamplingDto;
import com.xqls.server.dto.recive.SamplingSetBackDto;
import com.xqls.server.dto.recive.SwitchValveBackDto;
import com.xqls.server.dto.send.PingDto;
import com.xqls.server.netty.future.SyncWriteFuture;
import com.xqls.server.netty.future.SyncWriteMap;
import com.xqls.thread.SokectRunAble;
import com.xqls.thread.ThreadPoolExecutorUtil;
import com.xqls.util.ContextUtil;
import com.xqls.util.DictionaryEnums;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Date;

public class TcpServerHandler extends ChannelInboundHandlerAdapter{

    public TcpServerHandler(){
        super();
    }

    private static final Logger LOG = LoggerFactory
            .getLogger(TcpServerHandler.class);

    private OperationRecordBean  activeOperationRecordBean;
    //往channel map中添加channel信息
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        NettyTCPServer.getChannelMap().put(getIPString(ctx)+ctx.channel().hashCode(), ctx.channel());
        if(activeOperationRecordBean==null){
            activeOperationRecordBean=new OperationRecordBean();
            activeOperationRecordBean.setOperationType(DictionaryEnums.NET_WORK.getCode().toString());
            activeOperationRecordBean.setRecordContent("上线");

        }
        activeOperationRecordBean.setRecordTime(new Date());

    }
    //往channel map中删除channel信息
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        NettyTCPServer.getChannelMap().remove(getIPString(ctx)+ctx.channel().hashCode());
        SokectBiz sokectBiz=(SokectBiz)ContextUtil.getBean(SokectBiz.class);
        if(activeOperationRecordBean.getEnterpriseNo()!=null) {
            sokectBiz.channelInactive(activeOperationRecordBean.getEnterpriseNo());
        }
        activeOperationRecordBean=null;
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        SoketCommonDto soketCommonDto=(SoketCommonDto)msg;

        if(soketCommonDto!=null){
            try {


            LOG.info("接收到协议"+Thread.currentThread().getName()+soketCommonDto.toString());
                boolean deviceSchemaBean= ContextUtil.checkAddress(soketCommonDto.getAdress());
                if(!deviceSchemaBean){
                    return ;
                }
            LOG.info("keyMap:"+JSON.toJSONString(NettyTCPServer.getChannelKeyMap()));
            LOG.info("channleMap:"+JSON.toJSONString(NettyTCPServer.getChannelMap()));
            NettyTCPServer.checkChannelExsit(soketCommonDto.getAdress(),getIPString(ctx)+ctx.channel().hashCode());
            if(soketCommonDto instanceof SamplingSetBackDto|| soketCommonDto instanceof SwitchValveBackDto){
                SyncWriteFuture future = (SyncWriteFuture) SyncWriteMap.writeRecords.get(soketCommonDto.getAdress());
                if (future != null) {
                    future.setResponse(soketCommonDto);
                }
            } else  if(soketCommonDto instanceof ControlApparatusDto || soketCommonDto instanceof SamplingDto){
                Integer value;
                if(soketCommonDto instanceof ControlApparatusDto){
                    SyncWriteFuture future = (SyncWriteFuture) SyncWriteMap.waitValueResponses.get(soketCommonDto.getAdress());
                    if (future != null) {
                        value=future.getValue();
                        ControlApparatusDto controlApparatusDto=(ControlApparatusDto)soketCommonDto;
                        int different=value-controlApparatusDto.getAngle();
                        if(Math.abs(different)<=3){
                            future.setResponse(soketCommonDto);
                        }
                    }
                }else {
                    SyncWriteFuture future = (SyncWriteFuture) SyncWriteMap.waitSamplingResponses.get(soketCommonDto.getAdress());
                    if (future != null) {
                        value=future.getValue();
                        SamplingDto samplingDto=(SamplingDto)soketCommonDto;
                        if(value.intValue()==samplingDto.getStartUp().intValue()){
                            future.setResponse(soketCommonDto);
                        }
                    }

                }
            }



            //上线操作日志保存 上线只会触发一次
            if(activeOperationRecordBean.getEnterpriseNo()==null){
                activeOperationRecordBean.setEnterpriseNo(soketCommonDto.getAdress());
                soketCommonDto.setActiveOperationRecordBean(activeOperationRecordBean);
            }
           new  SokectRunAble(soketCommonDto).call();
            }catch (Exception e){
                throw  e;
            }finally {
                ReferenceCountUtil.release(soketCommonDto);
            }

        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("server channelReadComplete.."+ctx.channel());
        super.channelReadComplete(ctx);
        ctx.alloc().buffer().discardReadBytes();

    }
    @Override  
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        LOG.error("exceptionCaught!", cause);
       // ctx.close();
    }



    @Override//超时触发该方法
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
            throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state().equals(IdleState.ALL_IDLE)) {
                // 超时关闭channel
                ctx.close();
                String channelKey=getIPString(ctx)+ctx.channel().hashCode();
                LOG.info(channelKey  +  ":READER_IDLE");

                String adress= NettyTCPServer.getAdressByChannel(channelKey);
                if(StringUtils.isNotEmpty(adress)){
                    NettyTCPServer.getChannelMap().remove(adress);
                    NettyTCPServer.getChannelKeyMap().remove(adress);
                }

            } else if (event.state().equals(IdleState.WRITER_IDLE)) {
                LOG.info("WRITER_IDLE   ");
            } else if (event.state().equals(IdleState.READER_IDLE)) {

                // 发送心跳
                String adress= NettyTCPServer.getAdressByChannel(getIPString(ctx)+ctx.channel().hashCode());
                LOG.info("READER_IDLE"+adress);
                if(adress!=null){
                    PingDto pingDto=new PingDto();
                    pingDto.setAdress(adress);
                    ctx.channel().write(pingDto);
                    ctx.channel().flush();
                }

            }
        }
        super.userEventTriggered(ctx, evt);
    }


    public static String getIPString(ChannelHandlerContext ctx){
        String ipString = "";
        String socketString = ctx.channel().remoteAddress().toString();
        int colonAt = socketString.indexOf(":");
        ipString = socketString.substring(1, colonAt);
        return ipString;
    }
} 